﻿using Dyao.Book.Application.Abstractions;
using Dyao.Book.Contract;
using Dyao.Book.Entity;
using Dyao.Book.Repository.Abstractions;
using Foundation.Core;
using Foundation.Uow;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Foundation.DistributeLock;
using Foundation.Service.Bus.Core;
using Dyao.Book.BusApplication;

namespace Dyao.Book.Application
{
    public class BookCatalogueApplication : BaseApplication, IBookCatalogueApplication
    {
        private readonly IBookCatalogueRepository _bookCatalogueRepository;

        private readonly IBookRepository _bookepository;

        private readonly ILogger<BookCatalogueApplication> _logger;

        private readonly IDistributeLocker _distributeLocker;

        public BookCatalogueApplication(IBookCatalogueRepository bookCatalogueRepository,
            IBookRepository bookRepository,
            ILogger<BookCatalogueApplication> logger,
            IDistributeLocker distributeLocker)
        {
            _bookCatalogueRepository = bookCatalogueRepository;
            _bookepository = bookRepository;
            _logger = logger;
            _distributeLocker = distributeLocker;
        }

        /// <inheritdoc cref="IBookCatalogueApplication.GetListByBookIdAsync"/>
        public async Task<BookChapterDto> GetListByBookIdAsync(string bookId, CancellationToken cancellationToken)
        {
            using (var uow = UnitOfWorkManager.Begin(isReadDb: true))
            {
                var book = (await _bookepository.GetListByIdsAsync(new List<string>() { bookId }, b => new { Id = b.ID, b.SourceBookId, b.UpdateDateTime }, cancellationToken)).FirstOrDefault();
                if (book == null)
                    throw new BusinessException("书籍信息没有找到");

                var items = await _bookCatalogueRepository.GetListByBookIdAsync(bookId, bc => new
                {
                    Id = bc.ID,
                    Name = bc.CatalogueName,
                    bc.VolumeName,
                    bc.WordsNumber,
                    bc.CrawlComplete,
                    bc.IsFree,
                    bc.ContentLink,
                    bc.UpdateDateTime,
                }, cancellationToken);

                //// 爬取目录
                //if (items.IsNullOrEmpty())
                //{

                //    var cmd = new QiDianBookChaptersSpiderCommand()
                //    {
                //        Craw = new CrawCatalogueDto()
                //        {
                //            BookId = bookId,
                //            SourceBookId = book.SourceBookId.ToString()
                //        }
                //    };

                //    ServiceBus.SendOneWayCommand(cmd);
                //    _logger.LogInformation("爬取目录");
                //    throw new BusinessException("目录正在爬取请稍候重试!!!");
                //}
                //else
                //{
                //    var needCraws = items.Where(i => !i.CrawlComplete && i.IsFree);
                //    if (!needCraws.IsNullOrEmpty())
                //    {
                //        var cmd = new QiDianBookContentSpiderCommand()
                //        {
                //            BatchNo = book.Id,
                //            Craws = needCraws.Select(n => new CrawCatalogueContentDto()
                //            {
                //                BookCatalogueId = n.Id,
                //                ContentLink = n.ContentLink,
                //            }).ToList()
                //        };

                //        ServiceBus.SendOneWayCommand(cmd);
                //        _logger.LogInformation("爬取内容");
                //    }
                //}

                var result = new BookChapterDto()
                {
                    Items = items.Where(i => i.CrawlComplete).Select(i => new BookChapterItemDto()
                    {
                        Id = i.Id,
                        Name = i.Name,
                        VolumeName = i.VolumeName,
                        WordsNumber = i.WordsNumber,
                        LastUpdateDate = i.UpdateDateTime,
                    }).ToList(),
                    LastUpdateDate = book.UpdateDateTime,
                };
                return result;
            }
        }

        /// <inheritdoc cref="IBookCatalogueApplication.MatchChapterSourceAsync"/>
        public async Task<bool> MatchChapterSourceAsync(string bookId, CancellationToken cancellationToken)
        {
            var bookSourceRepo = GetService<IBookMatchSourceRepository>();
            var bookSourceMgr = GetService<IBookSourceWarehouseManager>();

            var lockKey = $"MatchChapterSource_{bookId}";
            var redLock = await _distributeLocker.CreateBlockingLockAsync(lockKey, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10), TimeSpan.FromSeconds(5), cancellationToken);

            await redLock.UsingNonBlockingLockAsync(async () =>
            {
                using (var uow = UnitOfWorkManager.Begin())
                {
                    var bookSourceEntities = await bookSourceRepo.GetListByBookIdAsync(bookId, cancellationToken);
                    var bookSources = ObjectMapper.Map<List<BookMatchSourceEntity>, List<BookSourceDto>>(bookSourceEntities);
                    if (bookSources.IsNullOrEmpty())
                        throw new BusinessException($"书籍编号:{bookId},未匹配书源,请匹配后再试");

                    var plugins = ServiceProvider.GetServices<IBusinessPlugin<BookChapterPluginsContext>>(); // 获取注入的插件

                    using (var scope = ServiceProvider.CreateScope())
                    {
                        using (var unitOfWork = UnitOfWorkManager.Begin(requiresNew: true))
                        {
                            var serviceProvider = scope.ServiceProvider;
                            var builder = new BusinessChainBuilder<BookChapterPluginsChain, BookChapterPluginsContext>(serviceProvider);
                            var sourceSettings = await bookSourceMgr.GetSourceWarehousesForCacheAsync(cancellationToken);

                            var args = new BookChapterPluginsArgs()
                            {
                                BookId = bookId,
                                BookSources = bookSources,
                                SourceSettings = sourceSettings,
                            };

                            foreach (var item in bookSources)
                            {
                                var currentSetting = sourceSettings.FirstOrDefault(s => s.SourceKey == item.SourceKey);
                                var currentPlugins = plugins.FirstOrDefault(p => ((BaseBookChapterPlugins)p).SourceKey == currentSetting.SourceKey);
                                builder.UsePlugin(currentPlugins.GetType());
                            }

                            var chain = builder.Build();
                            var context = new BookChapterPluginsContext(args);
                            await chain.RunAsync(context, cancellationToken);
                        }
                    }
                }

                var commonMgr = GetService<ICommonManager>();
                using (var unitOfWork = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true))
                {
                    var log = new OperationLogDto()
                    {
                        SourceId = bookId,
                        OperationType = OperationTypeEnum.Book,
                        OperationLog = "同步书籍章节链接"
                    };

                    try
                    {
                        await commonMgr.AddOperationLogsAsync(log);
                        await unitOfWork.CompleteAsync(cancellationToken);
                    }
                    catch (Exception)
                    {
                        await unitOfWork.RollbackAsync(cancellationToken);
                        throw;
                    }
                }
            },
            () =>
            {
                throw new BusinessException($"正在同步{bookId}相关章节源信息.");
            });

            return true;
        }

        /// <inheritdoc cref="IBookCatalogueApplication.MatchChapterSourceAsync"/>
        public async Task SyncBookChapterAsync(TaskCenterDto taskCenter, CancellationToken cancellationToken)
        {
            await ServiceProvider.BeginSingleTaskAsync(async (context) =>
            {
                var craw = context.GetQueryFilterModel<CrawCatalogueDto>();
                await context.AddProgressAsync(10); //更新进度
                await SyncBookChapterAsync(craw, cancellationToken);
            }, taskCenter, cancellationToken);
        }

        /// <inheritdoc cref="IBookCatalogueApplication.SyncBookFreeChapterContentAsync"/>
        public async Task SyncBookFreeChapterContentAsync(string bookId, CancellationToken cancellationToken)
        {
            using (var unitOfWork = UnitOfWorkManager.Begin(isReadDb: true))
            {
                var chapters = await _bookCatalogueRepository.GetNotCrawlCompalteByBookIdAsync(bookId, b => new
                {
                    BookCatalogueId = b.ID,
                    b.ContentLink,
                    b.SourceKey,
                    b.IsFree
                }, cancellationToken);

                var freeChapters = chapters.Where(c => c.IsFree).Select(c => new CrawCatalogueContentDto()
                {
                    BookCatalogueId = c.BookCatalogueId,
                    ContentLink = c.ContentLink,
                    SourceKey = c.SourceKey,
                });

                if (!freeChapters.Any()) return;

                var book = await _bookepository.GetByIdAsync(bookId, cancellationToken);
                ICommand cmd = null;
                switch (book.SourceType)
                {
                    case BookSourceType.QiDian:
                        cmd = new QiDianBookContentSpiderCommand()
                        {
                            BatchNo = bookId,
                            BookId = bookId,
                            Craws = freeChapters.ToList(),
                        };
                        break;
                    default:
                        throw new NotImplementedException($"未支持{book.SourceType.GetDescription()},该类型免费章节内容爬取");
                }

                ServiceBus.SendOneWayCommand(cmd);
            }

            var commonMgr = GetService<ICommonManager>();

            using (var unitOfWork = UnitOfWorkManager.Begin(isTransactional: true))
            {
                try
                {
                    var log = new OperationLogDto()
                    {
                        SourceId = bookId,
                        OperationType = OperationTypeEnum.Book,
                        OperationLog = "同步书籍免费章节内容"
                    };
                    await commonMgr.AddOperationLogsAsync(log);
                    await unitOfWork.CompleteAsync(cancellationToken);
                }
                catch (Exception)
                {
                    await unitOfWork.RollbackAsync(cancellationToken);
                    throw;
                }
            }
        }

        /// <inheritdoc cref="IBookCatalogueApplication.SyncBookChapterAsync(CrawCatalogueDto, CancellationToken)"/>
        public async Task SyncBookChapterAsync(CrawCatalogueDto craw, CancellationToken cancellationToken)
        {
            string resource = $"SyncBookChapterAsync_{craw.BookId}";
            var redLock = await _distributeLocker.CreateBlockingLockAsync(resource, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10), TimeSpan.FromSeconds(5), cancellationToken);
            await redLock.UsingNonBlockingLockAsync(async () =>
            {
                var commonMgr = GetService<ICommonManager>();

                switch (craw.BookSourceType)
                {
                    case BookSourceType.QiDian:
                        var spider = GetService<IQiDianBookCatalogueSpider>();
                        await spider.CrawCatalogueByBookAsync(craw, cancellationToken);
                        break;
                    default:
                        throw new NotImplementedException($"未支持{craw.BookSourceType.GetDescription()},该类型章节目录爬取");
                }

                // 更新同步时间
                using (var unitOfWork = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true))
                {
                    var bookEntities = new List<BookEntity>() {
                            new BookEntity()
                            {
                                ID = craw.BookId,
                                SyncChapterDate = DateTime.Now
                            }
                        };

                    var log = new OperationLogDto()
                    {
                        SourceId = craw.BookId,
                        OperationType = OperationTypeEnum.Book,
                        OperationLog = "同步书籍章节目录"
                    };

                    try
                    {
                        await _bookepository.BulkUpdateAsync(bookEntities, b => new { b.SyncChapterDate }, cancellationToken);
                        await commonMgr.AddOperationLogsAsync(log);
                        await unitOfWork.CompleteAsync(cancellationToken);
                    }
                    catch (Exception)
                    {
                        await unitOfWork.RollbackAsync(cancellationToken);
                        throw;
                    }
                }

                await SyncBookFreeChapterContentAsync(craw.BookId, cancellationToken); // 爬取免费章节
                // 匹配章节源
                var cmd = new SyncBookChapterSourceCommand()
                {
                    BookId = craw.BookId,
                };
                ServiceBus.SendOneWayCommand(cmd);

            }, () =>
            {
                throw new NotImplementedException($"{craw.BookId}-正在爬取目录结构,请稍后再试");
            });
        }
    }
}
